﻿using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Text;
using ManhXu.Common;

namespace ManhXu.RegistryEditor
{
    /// <summary>
    /// Registry Hot Key
    /// </summary>
    public enum RHKeys { CurrentUser, ClassesRoot, LocalMachine, Users, CurrentConfig };

    /// <summary>
    /// Registry Value Kind
    /// </summary>
    public enum RVKinds { String, Binary, DWord };

    /// <summary>
    /// An useful class to read/write/delete/count registry keys
    /// </summary>
    public class ModifyRegistry
    {
        //
        // Reference: http://www.c-sharpcorner.com/UploadFile/mahesh/WorkingwithWindowsRegistry11282005045112AM/WorkingwithWindowsRegistry.aspx
        // http://stackoverflow.com/questions/13185095/create-registry-key-not-the-usual: Runable
        // Test with link: http://www.wintips.org/increase-maximize-outlook-2003-2007-2010-2013-pst-file-size-limit/
        //
        //
        // Registry.SetValue(@"HKEY_CURRENT_USER\Software\Picrofo Software\", "", ""); //Tree
        // Registry.SetValue(@"HKEY_CURRENT_USER\Software\Picrofo Software\Subkey", "", ""); //Branch
        // Registry.SetValue(@"HKEY_CURRENT_USER\Software\Picrofo Software\Subkey", "Value Name", "Value", RegistryValueKind.String); //Branch's value
        // Registry.SetValue(@"HKEY_CURRENT_USER\Software\Picrofo Software\Another Subkey", "", ""); //Branch
        //

        public ModifyRegistry()
        { }

        /// <summary>
        /// Default value is Registry.LocalMachine 
        /// </summary>
        /// <param name="regHotkey"></param>
        public ModifyRegistry(RHKeys regHotkey)
            : this()
        {
            switch (regHotkey)
            {
                case RHKeys.CurrentUser:
                    this.baseRegistryKey = Registry.CurrentUser;
                    break;
                case RHKeys.ClassesRoot:
                    this.baseRegistryKey = Registry.ClassesRoot;
                    break;
                case RHKeys.LocalMachine:
                    this.baseRegistryKey = Registry.LocalMachine;
                    break;
                case RHKeys.Users:
                    this.baseRegistryKey = Registry.Users;
                    break;
                case RHKeys.CurrentConfig:
                    this.baseRegistryKey = Registry.CurrentConfig;
                    break;
                default:
                    this.baseRegistryKey = Registry.LocalMachine;
                    break;
            }
        }

        private bool isWriteLog = false;
        public bool IsWriteLog
        {
            get { return isWriteLog; }
            set { isWriteLog = value; }
        }

        private RegistryKey baseRegistryKey;

        public RegistryKey BaseRegistryKey
        {
            get { return baseRegistryKey; }
            set { baseRegistryKey = value; }
        }

        /// <summary>
        /// 
        /// Retrieves the value associated with the specified name, in the specified registry key
        /// 
        /// Example as below:
        ///     RegPath: Software\\Microsoft\\Office\\15.0\\Outlook\\PST
        ///     KeyName: LastCorruptStore
        /// 
        /// </summary>
        /// <param name="RegPath"></param>
        /// <param name="KeyName"></param>
        /// <returns>Retrieves the value associated with the specified name, in the specified registry key</returns>
        public string Read(string RegPath, string KeyName)
        {
            if (baseRegistryKey == null) { return string.Empty; }

            string hotKey = GetHotKey();//return value etc: HKEY_CURRENT_USER

            string registryPath = RegPath;

            if (RegPath.Contains("HKEY_"))
            {
                //
                // Make sure RegPath is etc: Software\\Microsoft\\Office\\15.0\\Outlook\\PST
                // maybe: HKEY_CURRENT_USER\\Software\\Microsoft\\Office\\15.0\\Outlook\\PST
                //
                registryPath = RegPath.Replace(hotKey, "");
            }

            //
            // Make sure RegPath is etc: Software\\Microsoft\\Office\\15.0\\Outlook\\PST
            // .................maybe: \\Software\\Microsoft\\Office\\15.0\\Outlook\\PST
            //
            RegPath = registryPath.TrimStart(new char[] { '\\' });

            RegistryKey pRegKey = baseRegistryKey;

            pRegKey = pRegKey.OpenSubKey(RegPath);

            Object subKey = pRegKey.GetValue(KeyName);

            if (subKey == null)
            {
                return null;
            }
            else
            {
                try
                {
                    return subKey.ToString();
                }
                catch (Exception e)
                {
                    // Has an error!
                    WriteLog(e, "Reading registry " + KeyName.ToUpper());
                    return null;
                }
            }
        }

        /// <summary>
        /// Sets the name/value pair on the specified registry key, using the specified registry data type. If the specified key does not exist, it is created.
        /// 
        /// Example as below:
        ///     RegPath: Software\\Microsoft\\Office\\15.0\\Outlook\\PST
        ///     KeyName: LastCorruptStore
        ///     Value: 
        ///     ValueKind: 
        /// </summary>
        /// <param name="RegPath"></param>
        /// <param name="KeyName"></param>
        /// <param name="Value"></param>
        /// <param name="ValueKind"></param>
        /// <returns></returns>
        public bool Write(string RegPath, string KeyName, object Value, RVKinds ValueKind)
        {
            try
            {
                if (baseRegistryKey == null) { return false; }

                string hotKey = GetHotKey();//return value etc: HKEY_CURRENT_USER

                RegistryValueKind kind = new RegistryValueKind();

                switch (ValueKind)
                {
                    case RVKinds.Binary:
                        kind = RegistryValueKind.Binary;
                        break;
                    case RVKinds.DWord:
                        kind = RegistryValueKind.DWord;
                        break;
                    case RVKinds.String:
                        kind = RegistryValueKind.String;
                        break;
                    default:
                        kind = RegistryValueKind.Unknown;
                        break;
                }

                if (RegPath.Contains("HKEY_"))
                {
                    Registry.SetValue(RegPath, KeyName, Value, kind);
                }
                else
                {
                    //
                    // Make sure RegPath is etc: HKEY_CURRENT_USER\\Software\\Microsoft\\Office\\15.0\\Outlook\\PST
                    // ......................................maybe: Software\\Microsoft\\Office\\15.0\\Outlook\\PST
                    //
                    string registryPath = string.Format("{0}\\{1}", hotKey, RegPath);
                    Registry.SetValue(registryPath, KeyName, Value, kind);
                }

                return true;
            }
            catch (Exception e)
            {
                // Has an error!
                WriteLog(e, "Writing registry " + KeyName.ToUpper());
                return false;
            }
        }

        private string GetHotKey()
        {
            string hotKey = string.Empty;

            if (this.BaseRegistryKey == null) return hotKey;

            if (this.BaseRegistryKey == Registry.CurrentUser)
            {
                hotKey = "HKEY_CURRENT_USER";
            }
            else if (this.BaseRegistryKey == Registry.ClassesRoot)
            {
                hotKey = "HKEY_CLASSES_ROOT";
            }
            else if (this.BaseRegistryKey == Registry.LocalMachine)
            {
                hotKey = "HKEY_LOCAL_MACHINE";
            }
            else if (this.BaseRegistryKey == Registry.Users)
            {
                hotKey = "HKEY_USERS";
            }
            else if (this.BaseRegistryKey == Registry.CurrentConfig)
            {
                hotKey = "HKEY_CURRENT_CONFIG";
            }
            else
            {
                hotKey = "HKEY_CURRENT_CONFIG";
            }

            return hotKey;
        }
        public bool DeleteKey(string KeyName)
        {
            try
            {

                return true;
            }
            catch (Exception e)
            {
                // Has an error!
                WriteLog(e, "Deleting key with KeyName: " + KeyName);
                return false;
            }
        }

        /// <summary>
        /// To delete a sub key and any child.
        /// </summary>
        public bool DeleteSubKeyTree(string KeyName)
        {
            try
            {
                return true;
            }
            catch (Exception e)
            {
                // Has an error!
                WriteLog(e, "Deleting sub key tree with KeyName: " + KeyName);
                return false;
            }
        }

        private void WriteLog(Exception e, string title)
        {
            List<string> errors = new List<string>();
            errors.Add(e.Message);
            errors.Add(title);
            Logger.WriteLog(errors);
        }
    }
}
